using System;
using System.Collections.Generic;
using System.Reflection;
using System.IO;
using CLELCore;

namespace opt
{
	public class OptimizationController
	{
		private Dictionary<String,Type> opts;
		private CLEL _clel;
		private CLELLogger _log;

		public OptimizationController(CLEL clel)
		{
			_clel = clel;
			_log = new CLELLogger("logs/opt.log");
		}


		public List<String> GetOptimizationNames()
		{
			opts = new Dictionary<String,Type>();
			LoadOptimizations();
			return new List<String>(opts.Keys);
		}

		public void DoOptimization(String name)
		{
			if(opts.ContainsKey(name))
			{
				Type t = opts[name];
				IOptimization op = (IOptimization)Activator.CreateInstance(t);
				op.DoOptimization(_clel,_log);
			}
			else
			{
				throw new Exception("Optimization does not exist");
			}
		}

		private void LoadOptimizations()
		{
			List<String> assemblies = GetFilesRecursively("lib/");

			Type [] types, interfaces;
			Assembly asm;
			int i,j,k;
			Type type;
			for(i = 0;i < assemblies.Count;i++)
			{
				asm = Assembly.LoadFrom(assemblies[i]);
				types = asm.GetTypes();
				for(j = 0;j < types.Length;j++)
				{
					type = types[j];
					interfaces = type.GetInterfaces();
					for(k = 0;k < interfaces.Length;k++)
					{
						if(interfaces[k].Name == "IOptimization")
						{
							IOptimization op = (IOptimization)Activator.CreateInstance(type);
							opts.Add(op.Name,type);
							break;
						}
					}
				}
			}
		}

		private List<String> GetFilesRecursively(String dir)
		{
			List<String> result = new List<String>();

			Stack<String> stack = new Stack<String>();
			stack.Push(dir);
			
			String current;
			while(stack.Count > 0)
			{
				current = stack.Pop();

				try
				{
					result.AddRange(Directory.GetFiles(current,"*.dll"));
					foreach(String new_dir in Directory.GetDirectories(current))
					{
						stack.Push(new_dir);
					}
				}
				catch
				{
				}
			}

			return result;
		}
	}
}
